#pragma once 
#include"InetAddr.hpp"
#include<iostream>
#include<string>
#include"Log.hpp"
#include<memory.h>


const int gbacklog = 5;
//模版方法模式
namespace socket_ns
{
    //错误类型
    enum {
        SOCKET_ERROR = 1,
        BIND_ERROR,
        LISTEN_ERROR,
        USAGE_ERROR
    };
    //Socket 接口类
    class Socket
    {
        public:
            //创建套接字接口
            virtual void CreateSocketOrDie() = 0;
            //将套接字和某个Ip地址和端口绑定
            //即告诉操作系统帮我监听(Ip + port)的消息
            virtual void BindSocketOrDie(InetAddr& addr) = 0;
            //将套接字设置为被动监听状态,并准备接受客户端的连接请求
            virtual void ListenSocketOrDie() = 0;
            //将从已建立连接的监听套接字中取出一个连接,返回新的通信套接字
            virtual int Accepter(InetAddr* addr) = 0;
            //客户段发起连接请求
            virtual bool Connetcor(InetAddr& addr) = 0;
            //设置socket2地址信息
            virtual void SetSocketAddrReuse() = 0;
            virtual int SockFd() = 0;
            //接收信息
            virtual int Recv(std::string* out) = 0;
            //发送信息
            virtual int Send(const std::string& in) = 0;
            //断开连接
            virtual void Close() = 0;

        public:
            //服务端创建listen监听套接字
            void BuildListenSocket(InetAddr& addr)
            {
                CreateSocketOrDie();
                SetSocketAddrReuse();
                BindSocketOrDie(addr);
                ListenSocketOrDie();
            }
            //客户端发起连接请求
            bool BuildClientSocket(InetAddr& addr)
            {
                CreateSocketOrDie();
                return Connetcor(addr);
            }
    };
    class TcpSocket : public Socket
    {
        public:;
            TcpSocket(int fd = -1)
            :_sockfd(fd)
            {

            }
            void  CreateSocketOrDie() override
            {
                //创建流式套接字
                _sockfd = ::socket(AF_INET,SOCK_STREAM,0);
                if(_sockfd < 0)
                {
                    LOG(FATAL, "sockfd error");
                    exit(SOCKET_ERROR);
                }
                LOG(DEBUG, "sockfd create success, sockfd is: %d\n", _sockfd);
            }
            void BindSocketOrDie(InetAddr& addr) override
            {
                //2. bind
                struct sockaddr_in local;
                memset(&local, 0, sizeof(local));
                local.sin_family  = AF_INET;
                local.sin_port = htons(addr.Port());
                local.sin_addr.s_addr = inet_addr(addr.Ip().c_str());
                
                int n = bind(_sockfd, (struct sockaddr*)&local, sizeof(local));
                if(n < 0)
                {
                    LOG(FATAL, "bind error\n");
                    exit(BIND_ERROR);
                }
                LOG(DEBUG, "bind success, new sockfd : %d \n", _sockfd);
            }
            void ListenSocketOrDie() override
            {
                int n = ::listen(_sockfd, gbacklog);
                if(n < 0)
                {
                    LOG(FATAL, "listen error\n");
                    exit(LISTEN_ERROR);
                }
                LOG(DEBUG, "listen success, sockfd is: %d\n", _sockfd);
            }
            int Accepter(InetAddr* addr) override
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int sockfd = ::accept(_sockfd, (struct sockaddr*)&peer, &len);
                if(sockfd < 0)
                {
                    LOG(WARNING, "accept error\n");
                    return -1;
                }
                *addr = peer;
                return sockfd;
            }
            virtual bool Connetcor(InetAddr& addr)
            {
                struct sockaddr_in server;
                //构建目标主机的socket信息
                memset(&server, 0, sizeof(server));
                server.sin_family = AF_INET;
                server.sin_addr.s_addr = inet_addr(addr.Ip().c_str());
                server.sin_port = htons(addr.Port());

                int n = connect(_sockfd, (struct sockaddr*)&server, sizeof(server));
                if(n < 0)
                {
                    std::cerr<<"connect error"<<std::endl;
                    return false;
                }
                return true;
            }
            void SetSocketAddrReuse() override
            {
                int opt = 1;
                ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
            }
            int Recv(std::string *out) override
            {
                char inbuffer[4096];
                ssize_t n = ::recv(_sockfd, inbuffer, sizeof(inbuffer)-1, 0);
                if(n > 0)
                {
                    inbuffer[n] = 0;
                    *out = inbuffer;
                }
                return n;
            }
            int Send(const std::string& in) override
            {
                int n = ::send(_sockfd, in.c_str(), in.size(), 0);
                return n;
            }
            int SockFd() override
            {
                return _sockfd;
            }
            void Close() override
            {
                if(_sockfd > -1)
                {
                    ::close(_sockfd);
                }
            }
        private:
            int _sockfd; 
    };
}